/*
 * =====================================================================================
 *
 *       Filename:  ncvector.h
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  2009年06月02日 11时05分03秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Ying Wang (WY), ywang@nlpr.ia.ac.cn
 *        Company:  Institute of Automation, Chinese Academy of Sciences
 *
 * =====================================================================================
 */
#ifndef NCVECTOR_H
#define NCVECTOR_H
#include <iostream>
#include "mathutils.h"
/**
 *
 */
template<typename T> class NCvector;

template<typename T>
inline  T  inner_product( const NCvector<T> &vec1, const NCvector<T> &vec2);

template<typename T>
inline T norm2(const NCvector<T> &vec1, const NCvector<T> &vec2);

template<typename T>
inline T norm2(const NCvector<T> &vec);

template <typename T>
class NCvector
{

	template<typename T1> 
		friend std::ostream& operator << (std::ostream& os, const NCvector<T1>& vec);
	template<typename T1>
		friend std::istream& operator >> (std::istream& is, NCvector<T1>& vec);
public:
	NCvector( );
	explicit NCvector( int n );
	NCvector( int n, T a );
	NCvector( int n, const T *a );
	NCvector( const NCvector<T> &rhs);
	
	NCvector<T>& operator = ( const NCvector<T> &rhs );
public:
	~NCvector( );
public:
	inline NCvector<T>& operator *= ( const T &m );
	inline NCvector<T>& operator += ( const T &m );

	inline NCvector<T>& operator += ( const NCvector<T> &vec );
	inline NCvector<T>& operator -= ( const NCvector<T> &vec );

	inline NCvector<T> operator + ( const NCvector<T> &vec ) const;
	inline NCvector<T> operator - ( const NCvector<T> &vec ) const;

public:
	inline T& operator [] ( int index );
	inline const T operator[] ( int index ) const;

	inline int size( ) const;
	inline void resize(int size);
private:
	int m_dim;
	T *data;
public:


};

template <typename T>
NCvector<T> :: NCvector( )
	: m_dim( 0 )
	, data( NULL )
{

}

template <typename T>
NCvector<T> :: NCvector( int n )
	: m_dim( n )
	, data( n>0 ? new T[n] : NULL )
{
}

template <typename T>
NCvector<T> :: NCvector( int n, T a )
	: m_dim( n )
	, data( m_dim>0 ? new T[m_dim] : NULL )
{
	for ( int i=0; i<n; i++ )
	{
		data[i] = a;
	}
}

template <typename T>
NCvector<T> :: NCvector( int n, const T *a )
	: m_dim( n )
	, data( n>0 ? new T[n] : NULL)
{
	for ( int i=0; i<n; i++ )
	{
		data[i] = a[i];
	}
}

template <typename T>
NCvector<T> :: NCvector( const NCvector<T> &rhs )
	: m_dim( rhs.m_dim )
	, data( m_dim>0 ? new T[m_dim] : NULL )
{
	for ( int i=0; i<m_dim; i++ )
	{
		data[i] = rhs.data[i];
	}
}

template<typename T>
NCvector<T>& NCvector<T>::operator = ( const NCvector<T> &rhs )
{
	if ( this != &rhs )
	{
		if ( m_dim != rhs.m_dim )
		{
			if( data != NULL)
				delete []data;
			m_dim = rhs.m_dim;
			data = m_dim>0 ? new T[m_dim] : NULL;
		}
		for ( int i=0; i<m_dim; i++ )
		{
			data[i] = rhs.data[i];
		}
	}
	return *this;
}
template<typename T>
NCvector<T> :: ~NCvector( )
{
	if ( data != NULL )
		delete []data;
}

template<typename T>
inline NCvector<T>& NCvector<T> :: operator *= ( const T &m )
{
	for ( int i=0; i<m_dim; i++ )
	{
		data[i] *= m;
	}
	return *this;
}

template<typename T>
inline NCvector<T>& NCvector<T> :: operator += ( const T &m )
{
	for ( int i=0; i<m_dim; i++ )
	{
		data[i] += m;
	}
	return *this;
}

template<typename T>
inline NCvector<T>& NCvector<T> :: operator += ( const NCvector<T> &vec )
{
	if ( m_dim == vec.m_dim )
	{
		for ( int i=0; i<m_dim; i++ )
		{
			data[i] += vec.data[i];
		}
		return *this;
	}
	else
	{
		std::cerr<< "Dim of the two vector must equal!" <<std::endl; 
		throw( "Dim of the two vector must equal!" );
	}
}

template<typename T>
inline NCvector<T>& NCvector<T> :: operator -= ( const NCvector<T> &vec )
{
	if ( m_dim == vec.m_dim )
	{
		for ( int i=0; i<m_dim; i++ )
		{
			data[i] -= vec.data[i];
		}
		return *this;
	}
	else
	{
	std::cerr<< "Dim of the two vector must equal!" <<std::endl; 

		throw( "Dimension of the two vector must equal!" );
	}
}

template<typename T>
inline NCvector<T> NCvector<T> :: operator + ( const NCvector<T> &vec ) const
{
	if ( m_dim == vec.m_dim )
	{
		NCvector<T> result(m_dim);
		for ( int i=0; i<m_dim; i++ )
		{
			result.data[i] = data[i] + vec.data[i];
		}
		return result;
	}
	else
	{
	std::cerr<< "Dim of the two vector must equal!" <<std::endl; 

		throw( "Dimension of the two vector must equal!" );
	}

}

template<typename T>
inline NCvector<T> NCvector<T> :: operator - ( const NCvector<T> &vec ) const
{
	if ( m_dim == vec.m_dim )
	{
		NCvector<T> result(m_dim);
		for ( int i=0; i<m_dim; i++ )
		{
			result.data[i] = data[i] - vec.data[i];
		}
		return result;
	}
	else
	{
	std::cerr<< "Dim of the two vector must equal!" <<std::endl; 

		throw( "Dimension of the two vector must equal!" );
	}
}

template<typename T>
inline T& NCvector<T> :: operator [] ( int index )
{
	if ( index>=0 && index<m_dim)
	{
		return data[index];
	}
	else
	{
		std::cerr<<" Vector index out of range"<<std::endl;
		throw("Index out of range");
	}
}

template<typename T>
inline const T NCvector<T>::operator [] (int index) const
{
	if( index>=0 && index<m_dim)
	{
		return data[index];
	}
	else
	{
		std::cerr << "Index out of range" << std::endl;
		throw("Index out of range");
	}
}
template<typename T>
inline int NCvector<T> :: size () const
{
	return m_dim;
}

template<typename T>
inline void NCvector<T> :: resize(int size)
{
	if(size != m_dim )
	{
		if( data != NULL)
			delete []data;
		m_dim = size;
		data = m_dim>0 ? new T[m_dim] : NULL;
	}
}

template<typename T1>
std::ostream& operator << (std::ostream& os, const NCvector<T1>& vec)
{
	for ( int i=0; i<vec.size(); i++ )
	{
		os << vec[i] <<" ";
	}
	return os;
}

template<typename T1>
std::istream& operator >> ( std::istream& is, NCvector<T1>& vec )
{
	int num=0;
	T1 tmp;
	while(is>>tmp)
		num++;
	vec.resize(num);
	is.clear();
	num = 0;
	is.seekg(0,std::ios::beg);
	while(is>>tmp)
	{
		vec.data[num] = tmp;
		num++;
	}
	return is;
}

template<typename T>
inline T inner_product( const NCvector<T> &vec1, const NCvector<T> &vec2)
{
	T result(0);
	if( vec1.size() == vec2.size() )
	{
		for ( int i=0; i<vec1.size(); i++ )
		{
			result += vec1[i]*vec2[i];
		}
		return result;
	}
	else
	{
		std::cerr<<"inner_product error"<<std::endl;
		throw( "Dimension of the two vector must equal!" );
	}
}

template<typename T>
inline T norm2( const NCvector<T> &vec1, const NCvector<T> &vec2)
{
	T result(0);
	if( vec1.size() == vec2.size() )
	{
		for( int i=0; i<vec1.size(); i++ )
			result += SQE(vec1[i] - vec2[i]);
		return result;
	}
	else
	{
		std::cerr << " norm2 error " << std::endl;
		throw( "norm2 error ");
	}
}

template<typename T>
inline T norm2 ( const NCvector<T> &vec )
{
	T result(0);
	for( int i=0; i<vec.size(); i++ )
		result += SQE(vec[i]);
	return result;
}
#endif
